#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <string>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <functional>
#include <unordered_map>

#include "Comm.hpp"
#include "Log.hpp"
#include "Nocopy.hpp"
#include "LockGuard.hpp"
#include "InetAddr.hpp"
#include "Thread.hpp"
#include "ThreadPool.hpp"
#include "Translate.hpp"

const static int default_backlog = 5;
using callback_t = function<void(int,InetAddr&)>;  // 回调函数
using task_t = function<void(void)>;  

class TcpServer : public Nocopy
{   
public:
    TcpServer(uint16_t port)
        :_port(port),_isrunning(false)
    {}

    void Init()
    {
        // 创建套接字
        _listensock = socket(AF_INET,SOCK_STREAM,0);
        if(_listensock < 0)
        {
            lg.LogMessage(Fatal,"create socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
            exit(Socket_err);
        }
        lg.LogMessage(Info , "create socket success , sockfd : %d\n",_listensock);

        int opt = 1;
        setsockopt(_listensock,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));

        // 填充网络信息，并绑定
        struct sockaddr_in ServerSockaddr;
        ServerSockaddr.sin_family = AF_INET;
        ServerSockaddr.sin_port = htons(_port);
        ServerSockaddr.sin_addr.s_addr = INADDR_ANY;
        socklen_t ServerLen = sizeof(ServerSockaddr);

        int n = bind(_listensock , (struct sockaddr*)&ServerSockaddr,ServerLen);
        if(n < 0)
        {
            lg.LogMessage(Fatal,"bind socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
            exit(Bind_err);
        }
        lg.LogMessage(Info , "bind socket success , sockfd : %d\n",_listensock);

        // 将listensock调节为监听模式
        int m = listen(_listensock,default_backlog);
        if(m < 0)
        {
            lg.LogMessage(Fatal,"listen socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
            exit(Listen_err);
        }
        lg.LogMessage(Info , "listen socket success , sockfd : %d\n",_listensock);

        // 启动线程池
        ThreadNS::ThreadPool<task_t>::GetInstance()->Start();
        // 添加默认任务
        RegisterFunc("defalutserver",bind(&TcpServer::DefalutServer,this,placeholders::_1,placeholders::_2));
    }

    // v4版本Service
    void Service(int sockfd,InetAddr& inetAddr)
    {
        char buffer[1024];
        while(true)
        {
            int n = read(sockfd,buffer,sizeof(buffer) - 1);
            if(n > 0)
            {
                buffer[n] = 0;
                std::cout << inetAddr.PrintDebug() << buffer << std::endl;

                std::string response = buffer;
                int m = write(sockfd,response.c_str(),response.size());
                
            }
            else if(n == 0)
            {
                lg.LogMessage(Warning,"client quit\n");
                break;
            }
            else
            {
                lg.LogMessage(Fatal,"read socket error , errno : %d , error string : %s\n",errno,strerror(errno));
                break;
            }
        }
    }

    // 效果：| ping | translate | transform |
    // 获取任务列表
    void DefalutServer(int sockfd,InetAddr& inetaddr)
    {
        (void)inetaddr;  // 这里未使用inetaddr，强转防止警告
        string task_list = "| ";
        for(auto task : _task_list)
        {
            if(task.first != "defalutserver")
            {
                task_list += task.first;
                task_list += " | ";
            }
        }
        write(sockfd,task_list.c_str(),task_list.size());
    }

    // 读取客户端所需服务
    string Read(int sockfd,InetAddr& inetaddr)
    {
        char buffer[1024];
        int n = read(sockfd,buffer,sizeof(buffer) - 1);
        if(n > 0)
        {
            buffer[n] = 0;
        }
        else if(n == 0)
        {
            lg.LogMessage(Warning,"client quit\n");
        }
        else
        {
            lg.LogMessage(Fatal,"read socket error , errno : %d , error string : %s\n",errno,strerror(errno));
        }
        return buffer;
    }

    // 任务转接
    void Routine(int sockfd,InetAddr& inetaddr)
    {
        _task_list["defalutserver"](sockfd,inetaddr);

        string type = Read(sockfd,inetaddr);
        lg.LogMessage(Info,"%s select %s\n",inetaddr.PrintDebug().c_str(),type.c_str());

        if(type == "ping")
        {
            _task_list[type](sockfd,inetaddr);
        }
        else if(type == "translate")
        {
            _task_list[type](sockfd,inetaddr);
        }
        else if(type == "transform")
        {
            _task_list[type](sockfd,inetaddr);
        }
        else
        {}

        close(sockfd);
    }

    // 注册任务
    void RegisterFunc(const string& type , callback_t cb)
    {
        _task_list[type] = cb;
    }

    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            // 获取连接
            struct sockaddr_in ClientSockaddr;
            socklen_t ClientLen = sizeof(ClientSockaddr);
            int sockfd = accept(_listensock,CONV(&ClientSockaddr),&ClientLen);

            if(sockfd < 0)
            {
                lg.LogMessage(Warning,"accept socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
                break;
            }
            lg.LogMessage(Info , "accept socket success , get a new sockfd : %d\n",sockfd);

            // v5版本，线程池版本
            // 其他四个版本在TcpServer copy.hpp中
            
            // task_t task = bind(&TcpServer::Service,this,sockfd,InetAddr(ClientSockaddr));
            // 将任务添加到线程池中
            task_t task = bind(&TcpServer::Routine,this,sockfd,InetAddr(ClientSockaddr));
            ThreadNS::ThreadPool<task_t>::GetInstance()->Push(task);
        }
    }

    ~TcpServer()
    {}

private:
    uint16_t _port;
    int _listensock;
    bool _isrunning;

    // 任务列表
    unordered_map<string,callback_t> _task_list;
};